﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BrickAndBrick
{

    public class BBMap
    {
        //行
        public const int ROW = 14;
        //列
        public const int COL = 10;
        public List<List<int>> mapList;

        public BBMap()
        {
            mapList = new List<List<int>>();
            for (int i = 0; i < ROW; i++)
            {
                List<int> temp = new List<int>();
                for (int j = 0; j < COL; j++)
                {
                    temp.Add(0);
                }
                mapList.Add(temp);
            }
        }

        public BBMap(List<List<int>> mapList)
        {
            this.mapList = mapList;
        }

        public int GetTotalNums()
        {
            int count = 0;
            foreach (var item in mapList)
            {
                foreach (var item1 in item)
                {
                    if (item1 != 0)
                    {
                        count++;
                    }
                }
            }
            return count;
        }

        public BBStep TryLeft(int x, int y)
        {
            if (mapList[x][y] == 0)
            {
                return null;
            }
            //计算到左侧首个空挡有多少砖块           
            int brickNums = 0;
            while (y - brickNums >= 0)
            {
                if (mapList[x][y - brickNums] == 0)
                {
                    break;
                }
                brickNums++;
            }
            brickNums--;
            //Console.WriteLine("bn:" + brickNums); ;
            //计算判断左侧是否有剩余空间            
            int emptyNums = 0;
            while (y - brickNums - emptyNums >= 0)
            {
                if (y - brickNums - emptyNums - 1 < 0 || mapList[x][y - brickNums - emptyNums - 1] != 0)
                {
                    break;
                }
                emptyNums++;
            }
            //Console.WriteLine("en:" + emptyNums);
            //依次与路径上的上下砖块比对，是否有相同砖块
            for (int steps = 0; steps <= emptyNums; steps++)
            {
                //上边
                int nearestX = FindNearestUp(x, y - steps);
                if (nearestX != -1 && mapList[x][y] == mapList[nearestX][y - steps])
                {
                    BBMap tempMap = this.Clone();
                    if (steps > 0)
                    {
                        for (int i = brickNums; i > 0; i--)
                        {
                            int temp = tempMap.mapList[x][y - i];
                            tempMap.mapList[x][y - i - steps] = temp;
                            tempMap.mapList[x][y - i] = 0;
                        }
                    }
                    tempMap.mapList[nearestX][y - steps] = 0;
                    tempMap.mapList[x][y] = 0;
                    return new BBStep(tempMap, x * BBMap.COL + y, 0, steps);
                }
                //下边
                nearestX = FindNearestDown(x, y - steps);
                if (nearestX != -1 && mapList[x][y] == mapList[nearestX][y - steps])
                {
                    BBMap tempMap = this.Clone();
                    if (steps > 0)
                    {
                        for (int i = brickNums; i > 0; i--)
                        {
                            int temp = tempMap.mapList[x][y - i];
                            tempMap.mapList[x][y - i - steps] = temp;
                            tempMap.mapList[x][y - i] = 0;
                        }
                    }
                    tempMap.mapList[nearestX][y - steps] = 0;
                    tempMap.mapList[x][y] = 0;
                    return new BBStep(tempMap, x * BBMap.COL + y, 0, steps);
                }
            }
            return null;
        }

        public BBStep TryUp(int x, int y)
        {
            if (mapList[x][y] == 0)
            {
                return null;
            }
            //计算到上方首个空挡有多少砖块
            int brickNums = 0;
            while (x - brickNums >= 0)
            {
                if (mapList[x - brickNums][y] == 0)
                {
                    break;
                }
                brickNums++;
            }
            brickNums--;
            //Console.WriteLine("bn:" + brickNums); ;
            //计算判断上方是否有剩余空间
            int emptyNums = 0;
            while (x - brickNums - emptyNums >= 0)
            {
                if (x - brickNums - emptyNums - 1 < 0 || mapList[x - brickNums - emptyNums - 1][y] != 0)
                {
                    break;
                }
                emptyNums++;
            }
            //Console.WriteLine("en:" + emptyNums);
            //依次与路径上的左右砖块比对，是否有相同砖块
            for (int steps = 0; steps <= emptyNums; steps++)
            {
                //左边
                int nearestY = FindNearestLeft(x - steps, y);
                if (nearestY != -1 && mapList[x][y] == mapList[x - steps][nearestY])
                {
                    BBMap tempMap = this.Clone();
                    if (steps > 0)
                    {
                        for (int i = brickNums; i > 0; i--)
                        {
                            int temp = tempMap.mapList[x - i][y];
                            tempMap.mapList[x - i - steps][y] = temp;
                            tempMap.mapList[x - i][y] = 0;
                        }
                    }
                    tempMap.mapList[x - steps][nearestY] = 0;
                    tempMap.mapList[x][y] = 0;
                    return new BBStep(tempMap, x * BBMap.COL + y, 1, steps);
                }
                //右边
                nearestY = FindNearestRight(x - steps, y);
                if (nearestY != -1 && mapList[x][y] == mapList[x - steps][nearestY])
                {
                    BBMap tempMap = this.Clone();
                    if (steps > 0)
                    {
                        for (int i = brickNums; i > 0; i--)
                        {
                            int temp = tempMap.mapList[x - i][y];
                            tempMap.mapList[x - i - steps][y] = temp;
                            tempMap.mapList[x - i][y] = 0;
                        }
                    }
                    tempMap.mapList[x - steps][nearestY] = 0;
                    tempMap.mapList[x][y] = 0;
                    return new BBStep(tempMap, x * BBMap.COL + y, 1, steps);
                }
            }
            return null;
        }

        public BBStep TryRight(int x, int y)
        {
            if (mapList[x][y] == 0)
            {
                return null;
            }
            //计算到右侧首个空挡有多少砖块
            int brickNums = 0;
            while (y + brickNums < COL)
            {
                if (mapList[x][y + brickNums] == 0)
                {
                    break;
                }
                brickNums++;
            }
            brickNums--;
            // Console.WriteLine("bn:" + brickNums);
            //计算判断右侧是否有剩余空间
            int emptyNums = 0;
            while (y + brickNums + emptyNums < COL)
            {
                if (y + brickNums + emptyNums + 1 >= COL || mapList[x][y + brickNums + emptyNums + 1] != 0)
                {
                    break;
                }
                emptyNums++;
            }
            //  Console.WriteLine("en:" + emptyNums);
            //依次与路径上的上下砖块比对，是否有相同砖块
            for (int steps = 0; steps <= emptyNums; steps++)
            {
                //上边
                int nearestX = FindNearestUp(x, y + steps);
                if (nearestX != -1 && mapList[x][y] == mapList[nearestX][y + steps])
                {
                    BBMap tempMap = this.Clone();
                    if (steps > 0)
                    {
                        for (int i = brickNums; i > 0; i--)
                        {
                            int temp = tempMap.mapList[x][y + i];
                            tempMap.mapList[x][y + i + steps] = temp;
                            tempMap.mapList[x][y + i] = 0;
                        }
                    }
                    tempMap.mapList[nearestX][y + steps] = 0;
                    tempMap.mapList[x][y] = 0;
                    return new BBStep(tempMap, x * BBMap.COL + y, 2, steps);
                }
                //下边
                nearestX = FindNearestDown(x, y + steps);
                if (nearestX != -1 && mapList[x][y] == mapList[nearestX][y + steps])
                {
                    BBMap tempMap = this.Clone();
                    if (steps > 0)
                    {
                        for (int i = brickNums; i > 0; i--)
                        {
                            int temp = tempMap.mapList[x][y + i];
                            tempMap.mapList[x][y + i + steps] = temp;
                            tempMap.mapList[x][y + i] = 0;
                        }
                    }
                    tempMap.mapList[nearestX][y + steps] = 0;
                    tempMap.mapList[x][y] = 0;
                    return new BBStep(tempMap, x * BBMap.COL + y, 2, steps);
                }
            }
            return null;
        }

        public BBStep TryDown(int x, int y)
        {
            if (mapList[x][y] == 0)
            {
                return null;
            }
            //计算到下方首个空挡有多少砖块
            int brickNums = 0;
            while (x + brickNums < ROW)
            {
                if (mapList[x + brickNums][y] == 0)
                {
                    break;
                }
                brickNums++;
            }
            brickNums--;
            //Console.WriteLine("bn:" + brickNums);
            //计算判断下方是否有剩余空间
            int emptyNums = 0;
            while (x + brickNums + emptyNums < ROW)
            {
                if (x + brickNums + emptyNums + 1 >= ROW || mapList[x + brickNums + emptyNums + 1][y] != 0)
                {
                    break;
                }
                emptyNums++;
            }
            //Console.WriteLine("en:" + emptyNums);
            //依次与路径上的左右砖块比对，是否有相同砖块
            for (int steps = 0; steps <= emptyNums; steps++)
            {
                //左边
                int nearestY = FindNearestLeft(x + steps, y);
                if (nearestY != -1 && mapList[x][y] == mapList[x + steps][nearestY])
                {
                    BBMap tempMap = this.Clone();
                    if (steps > 0)
                    {
                        for (int i = brickNums; i > 0; i--)
                        {
                            int temp = tempMap.mapList[x + i][y];
                            tempMap.mapList[x + i + steps][y] = temp;
                            tempMap.mapList[x + i][y] = 0;
                        }
                    }
                    tempMap.mapList[x + steps][nearestY] = 0;
                    tempMap.mapList[x][y] = 0;
                    return new BBStep(tempMap, x * BBMap.COL + y, 3, steps);
                }
                //右边
                nearestY = FindNearestRight(x + steps, y);
                if (nearestY != -1 && mapList[x][y] == mapList[x + steps][nearestY])
                {
                    BBMap tempMap = this.Clone();
                    if (steps > 0)
                    {
                        for (int i = brickNums; i > 0; i--)
                        {
                            int temp = tempMap.mapList[x + i][y];
                            tempMap.mapList[x + i + steps][y] = temp;
                            tempMap.mapList[x + i][y] = 0;
                        }
                    }
                    tempMap.mapList[x + steps][nearestY] = 0;
                    tempMap.mapList[x][y] = 0;
                    return new BBStep(tempMap, x * BBMap.COL + y, 3, steps);
                }
            }
            return null;
        }

        public BBMap Clone()
        {
            BBMap newMap = new BBMap();
            for (int x = 0; x < mapList.Count; x++)
            {
                for (int y = 0; y < mapList[x].Count; y++)
                {
                    newMap.mapList[x][y] = this.mapList[x][y];
                }
            }
            return newMap;
        }
        /// <summary>
        /// 寻找上方最近的非0砖块在第几行
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns>如有返回上方最近砖块的行数，否则返回-1</returns>
        public int FindNearestUp(int x, int y)
        {
            for (int nearestX = x - 1; nearestX > -1; nearestX--)
            {
                if (mapList[nearestX][y] == 0)
                {
                    continue;
                }
                else
                {
                    return nearestX;
                }
            }
            return -1;
        }

        public int FindNearestDown(int x, int y)
        {
            for (int nearestX = x + 1; nearestX < BBMap.ROW; nearestX++)
            {
                if (mapList[nearestX][y] == 0)
                {
                    continue;
                }
                else
                {
                    return nearestX;
                }
            }
            return -1;
        }

        public int FindNearestLeft(int x, int y)
        {
            for (int nearestY = y - 1; nearestY > -1; nearestY--)
            {
                if (mapList[x][nearestY] == 0)
                {
                    continue;
                }
                else
                {
                    return nearestY;
                }
            }
            return -1;
        }
        public int FindNearestRight(int x, int y)
        {
            for (int nearestY = y + 1; nearestY < BBMap.COL; nearestY++)
            {
                if (mapList[x][nearestY] == 0)
                {
                    continue;
                }
                else
                {
                    return nearestY;
                }
            }
            return -1;
        }
        public bool IsEmpty()
        {
            foreach (var row in mapList)
            {
                foreach (var brick in row)
                {
                    if (brick != 0)
                    {
                        return false;
                    }
                }
            }
            return true;
        }

        public override string ToString()
        {
            string str = string.Empty;
            foreach (var r in mapList)
            {
                foreach (var c in r)
                {
                    str += (c + "\t");
                }
                str += ("\r\n");
            }
            return str;
        }
    }
}
